package com.zjl.学习.第03章_步骤Shop.E_多步骤执行条件分支控制JobExecutionDecider;

import com.zjl.springbatch.util.OutColour;
import com.zjl.学习.第03章_步骤Shop.C1_居于块Tasklet.C1_居于块Tasklet;
import com.zjl.学习.第03章_步骤Shop.D_步骤监听器.MyChunkListener;
import com.zjl.学习.第03章_步骤Shop.D_步骤监听器.MyStepExecutionListener;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
import org.springframework.batch.core.job.flow.JobExecutionDecider;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.item.*;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.nio.charset.Charset;
import java.util.List;
import java.util.Random;

/**
 * 几个注意点：
 * 1> on 方法表示条件， 上一个步骤返回值，匹配指定的字符串，满足后执行后续 to 步骤
 * 2> * 为通配符，表示能匹配任意返回值   ? 表示匹配任意单个字符
 * 3> from 表示从某个步骤开始进行条件判断
 * 4> 分支判断结束，流程以end方法结束，表示if/else逻辑结束
 * 5> on 方法中字符串取值于 ExitStatus 类常量，当然也可以自定义。
 *
 *
 */
@SpringBootApplication
@EnableBatchProcessing//开启spring batch
public class E_多步骤执行条件分支控制JobExecutionDecider {
    /**
     * ExitStatus.UNKNOWN //未知，不知道的状态
     * ExitStatus.EXECUTING //执行
     *      表示处理时的连续状态仍在发生，因此不需要采取进一步行动。
     *      用于异步执行场景，其中处理发生在另一个线程或进程，调用者不需要等待结果
     * ExitStatus.COMPLETED //已完成的加工
     * ExitStatus.NOOP //表示没有处理的作业
     * ExitStatus.FAILED  //有误差的已完成处理。
     * ExitStatus.STOPPED  //表示已完成的加工 中断状态停止
     * //每个 step 只会执行一遍  即 只会进入一个判断的成立语句（即 start/from），成立过一次后，就不能再次进入to了
     * //from 就是如果   on 就是 from的值是否等于此值  等于的话执行  to
     */
    public static void main(String[] args) {
//        args = new String[]{"name=张蛟龙3"};//模拟 入参
        System.setProperty("spring.profiles.active","01");//  同理 --spring.profiles.active=xxx

        SpringApplication.run(E_多步骤执行条件分支控制JobExecutionDecider.class, args);
        System.out.println("***********启动完毕**当前编码:" + Charset.defaultCharset().name() + "****************");

    }
    @Autowired//@EnableBatchProcessing 这个注解帮你从 spring batch 的配置文件中加载了
    private JobLauncher jobLauncher;//Job 启动器
    @Autowired//Job 构造工厂
    private JobBuilderFactory jobBuilderFactory;
    @Autowired//构建 Step
    private StepBuilderFactory stepBuilderFactory;
    @Bean//任务 Tasklet 这是最简单的    还有Chunk块处理
    public Tasklet tasklet030(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet030*******************");
//                if(true) throw new RuntimeException("测试fail结果");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Tasklet tasklet031(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet031*******************");

                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Tasklet tasklet032(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet032*******************");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Tasklet tasklet033(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet033*******************");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Tasklet tasklet03X(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet03X错误*******************");
                if(true) throw new Exception("模拟异常");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Tasklet tasklet03Restart(){
        return new Tasklet() {
            @Override
            public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
                OutColour.out.printlnRed("****************tasklet03Restart*******************");
                return RepeatStatus.FINISHED;//已完成
            }
        };
    }
    @Bean
    public Step step030Decider() throws Exception {
        return stepBuilderFactory.get("step030Decider").tasklet(tasklet030()).build();
    }
    @Bean
    public Step step031Decider() throws Exception {

        return stepBuilderFactory.get("step031Decider").tasklet(tasklet031()).build();
    }
    @Bean
    public Step step032Decider() throws Exception {

        return stepBuilderFactory.get("step032Decider").tasklet(tasklet032()).build();
    }
    @Bean
    public Step step033Decider() throws Exception {

        return stepBuilderFactory.get("step033Decider").tasklet(tasklet033()).build();
    }
    @Bean
    public Step step03XDecider() throws Exception {

        return stepBuilderFactory.get("step03XDecider").tasklet(tasklet03X()).build();
    }
    @Bean
    public Step step03Restart() throws Exception {

        return stepBuilderFactory.get("step03Restart").tasklet(tasklet03Restart()).build();
    }

    @Bean// 会自己找 指定符合的类传进去入参
    public Job job003() throws Exception {
        /**
         * ExitStatus.UNKNOWN //未知，不知道的状态
         * ExitStatus.EXECUTING //执行
         *      表示处理时的连续状态仍在发生，因此不需要采取进一步行动。
         *      用于异步执行场景，其中处理发生在另一个线程或进程，调用者不需要等待结果
         * ExitStatus.COMPLETED //已完成的加工
         * ExitStatus.NOOP //表示没有处理的作业，无效状态，表示没执行
         * ExitStatus.FAILED  //有误差的已完成处理。  抛出异常
         * ExitStatus.STOPPED  //表示已完成的加工 中断状态停止
         */
        return jobBuilderFactory.get("job003Decider123123213问123")
                //每个 step 只会执行一遍  即 只会进入一个判断的成立语句（即 start/from），成立过一次后，就不能再次进入to了
                //from 就是如果   on 就是 from的值是否等于此值  等于的话执行  to
                //.start(step030Decider()).on(ExitStatus.FAILED.getExitCode()).to(step031Decider())
                //.from(step030Decider()).on(ExitStatus.COMPLETED.getExitCode()).to(step032Decider())
                //.next(step033Decider()).on("*").to(step031Decider())
                //.end()//结束

                //自定义的返回
//                .start(step030Decider())//执行初始

//                .start(step03XDecider())//模拟异常，异常或可以继续调用执行，直到成功后再调用就不可执行了

//                .next(myStatusDecider)//根据此类的方法内部得值 next 就表示 从此处开始新的  多次next会死循环  //TODO 不太懂具体逻辑
//                .from(myStatusDecider).on("A").to(step031Decider())//返回的值为指定值执行
//                .from(myStatusDecider).on("B").to(step032Decider())//返回的值为指定值执行
//                .from(myStatusDecider).on("C").to(step033Decider())//返回的值为指定值执行
//                .from(myStatusDecider).on("D").fail()//表示流程失败结束 FAILED
//                .from(myStatusDecider).on("*").stop()//表示流程失败结束 FAILED
//                .end()//表示流程成功的结束 COMPLETED
//                .incrementer(new RunIdIncrementer())

//                .start(step03XDecider()).on(ExitStatus.FAILED.getExitCode()).end()//失败 但是 end 会将前面的失败步骤改为成功结束
//                .from(step031Decider()).on("*").to(step030Decider()).end()

//                .start(step03XDecider()).on(ExitStatus.FAILED.getExitCode()).fail()//fail  失败的结束  但是如果 start成功执行了，下次再执行，不会执行
//                .end()

                //将失败状态转为停止状态，为后续重启准备 这时 step03XDecider状态为   ABANDONED(被抛弃的)  表示次运行陪抛弃了，是失败的，
                // 在此次重启会从 错误的 之后执行 即 stopAndRestart 之后不包括 stopAndRestart
                .start(step031Decider())
                .next(step03XDecider()).on(ExitStatus.FAILED.getExitCode()).stopAndRestart(step03Restart()).next(step033Decider())
                .end()



                .build();
    }
    @Autowired//构建 Step
    private MyStatusDecider myStatusDecider;
}

@Component//自定义决策器
class MyStatusDecider implements JobExecutionDecider {
    @Override
    public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
        long ret = new Random().nextInt(3);
        if(ret == 0){
            return new FlowExecutionStatus("A");
        }else if(ret == 1){
            return new FlowExecutionStatus("B");
        }else{
            return new FlowExecutionStatus("C");
        }
    }
}
